﻿using System;
using System.Diagnostics;
using System.Linq;
using System.Security.Claims;
using System.Security.Principal;
using System.Threading.Tasks;
using IdentityServer4.Events;
using IdentityServer4.Models;
using IdentityServer4.Services;
using IdentityServer4.Stores;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Volo.Abp.Account.Public.Web;
using Volo.Abp.Account.Public.Web.Pages.Account;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Settings;
using Volo.Abp.Uow;

namespace Volo.Abp.Account.Web.Pages.Account
{
	[ExposeServices(
		typeof(LoginModel)
	)]
	public class IdentityServerSupportedLoginModel : LoginModel
	{
		protected IIdentityServerInteractionService Interaction { get; }

		protected IClientStore ClientStore { get; }

		protected IEventService IdentityServerEvents { get; }

		public IdentityServerSupportedLoginModel(IAuthenticationSchemeProvider schemeProvider, IOptions<AbpAccountOptions> accountOptions, IIdentityServerInteractionService interaction, IClientStore clientStore, IEventService identityServerEvents)
			:base(schemeProvider, accountOptions)
		{
			this.Interaction = interaction;
			this.ClientStore = clientStore;
			this.IdentityServerEvents = identityServerEvents;
		}

		public override async Task OnGetAsync()
		{
			base.LoginInput = new LoginModel.LoginInputModel();
			var context = await this.Interaction.GetAuthorizationContextAsync(base.ReturnUrl);
			if (context != null)
			{
				base.LoginInput.UserNameOrEmailAddress = context.LoginHint;
				string text = context.Parameters["__tenant"];
				if (!string.IsNullOrEmpty(text))
				{
					base.CurrentTenant.Change(new Guid?(Guid.Parse(text)), null);
					base.Response.Cookies.Append("__tenant", text);
				}
			}
			if (((context != null) ? context.IdP : null) != null)
			{
				base.LoginInput.UserNameOrEmailAddress = context.LoginHint;
				base.ExternalProviders = new LoginModel.ExternalProviderModel[]
				{
					new LoginModel.ExternalProviderModel
					{
						AuthenticationScheme = context.IdP
					}
				};
			}
			else
			{
				var providers = await this.GetExternalProviders();
				base.ExternalProviders = providers.ToList<LoginModel.ExternalProviderModel>();
				base.EnableLocalLogin = await base.SettingProvider.IsTrueAsync("Abp.Account.EnableLocalLogin");
				base.IsSelfRegistrationEnabled = await base.SettingProvider.IsTrueAsync("Abp.Account.IsSelfRegistrationEnabled");
				AuthorizationRequest authorizationRequest3 = context;
				if (((context != null) ? context.ClientId : null) != null)
				{
					//此处逻辑需补上
					//IdentityServerSupportedLoginModel.<> c__DisplayClass10_0 CS$<> 8__locals1 = new IdentityServerSupportedLoginModel.<> c__DisplayClass10_0();
					//CS$<> 8__locals1.client = await this.ClientStore.FindEnabledClientByIdAsync(context.ClientId);
					//if (CS$<> 8__locals1.client != null)
					//{
					//	base.EnableLocalLogin = CS$<> 8__locals1.client.EnableLocalLogin;
					//	if (CS$<> 8__locals1.client.IdentityProviderRestrictions != null && CS$<> 8__locals1.client.IdentityProviderRestrictions.Any<string>())
					//	{
					//		providers = (from provider in providers
					//					 where CS$<> 8__locals1.client.IdentityProviderRestrictions.Contains(provider.AuthenticationScheme)
					//		select provider).ToList<LoginModel.ExternalProviderModel>();
					//	}
					//}
				}
				base.ExternalProviders = providers.ToArray();
				if (base.IsExternalLoginOnly)
				{
					throw new NotImplementedException();
				}
			}
		}

		[UnitOfWork]
		public override async Task<IActionResult> OnPostAsync(string action)
		{
			var externalProviders = await this.GetExternalProviders();
			base.ExternalProviders = externalProviders;
			base.EnableLocalLogin = await base.SettingProvider.IsTrueAsync("Abp.Account.EnableLocalLogin");
			base.IsSelfRegistrationEnabled = await base.SettingProvider.IsTrueAsync("Abp.Account.IsSelfRegistrationEnabled");
			IActionResult result;
			if (action == "Cancel")
			{
				var request = await this.Interaction.GetAuthorizationContextAsync(base.ReturnUrl);
				if (request == null)
				{
					result = base.Redirect("~/");
				}
				else
				{
					await this.Interaction.GrantConsentAsync(request, ConsentResponse.Denied, null);
					result = base.Redirect(base.ReturnUrl);
				}
			}
			else
			{
				this.ValidateModel();
				await this.ReplaceEmailToUsernameOfInputIfNeeds();
				var signInResult = await base.SignInManager.PasswordSignInAsync(base.LoginInput.UserNameOrEmailAddress, base.LoginInput.Password, base.LoginInput.RememberMe, true);
				if (signInResult.RequiresTwoFactor)
				{
					result = this.RedirectToPage("./SendSecurityCode", new
					{
						returnUrl = base.ReturnUrl,
						returnUrlHash = base.ReturnUrlHash,
						rememberMe = base.LoginInput.RememberMe
					});
				}
				else if (signInResult.IsLockedOut)
				{
					base.Alerts.Warning(base.L["UserLockedOutMessage"]);
					result = this.Page();
				}
				else if (signInResult.IsNotAllowed)
				{
					base.Alerts.Warning(base.L["LoginIsNotAllowed"]);
					result = this.Page();
				}
				else if (!signInResult.Succeeded)
				{
					base.Alerts.Danger(base.L["InvalidUserNameOrPassword"]);
					result = this.Page();
				}
				else
				{
					var identityUser = await base.UserManager.FindByNameAsync(base.LoginInput.UserNameOrEmailAddress);
					if (identityUser == null)
					{
						identityUser = await base.UserManager.FindByEmailAsync(base.LoginInput.UserNameOrEmailAddress);
					}
					await this.IdentityServerEvents.RaiseAsync(new UserLoginSuccessEvent(identityUser.UserName, identityUser.Id.ToString(), identityUser.UserName));
					result = base.RedirectSafely(base.ReturnUrl, base.ReturnUrlHash);
				}
			}
			return result;
		}

		[UnitOfWork]
		public override async Task<IActionResult> OnPostExternalLogin(string provider)
		{
			IActionResult result2;
			if (this.AccountOptions.WindowsAuthenticationSchemeName == provider)
			{
				var result = await this.ProcessWindowsLoginAsync();
				result2 = result;
			}
			else
			{
				result2 = await base.OnPostExternalLogin(provider);
			}
			return result2;
		}

		protected virtual async Task<IActionResult> ProcessWindowsLoginAsync()
		{
			var authenticateResult = await base.HttpContext.AuthenticateAsync(this.AccountOptions.WindowsAuthenticationSchemeName);
			WindowsPrincipal windowsPrincipal = ((authenticateResult != null) ? authenticateResult.Principal : null) as WindowsPrincipal;
			IActionResult result;
			if (windowsPrincipal == null)
			{
				result = this.Challenge(new string[]
				{
					this.AccountOptions.WindowsAuthenticationSchemeName
				});
			}
			else
			{
				AuthenticationProperties props = new AuthenticationProperties
				{
					RedirectUri = base.Url.Page("./Login", "ExternalLoginCallback", new
					{
						base.ReturnUrl,
						base.ReturnUrlHash
					}),
					Items =
					{
						{
							"scheme",
							this.AccountOptions.WindowsAuthenticationSchemeName
						}
					}
				};
				ClaimsIdentity claimsIdentity = new ClaimsIdentity(this.AccountOptions.WindowsAuthenticationSchemeName);
				claimsIdentity.AddClaim(new Claim("sub", windowsPrincipal.Identity.Name));
				claimsIdentity.AddClaim(new Claim("name", windowsPrincipal.Identity.Name));
				await base.HttpContext.SignInAsync("idsrv.external", new ClaimsPrincipal(claimsIdentity), props);
				result = base.RedirectSafely(props.RedirectUri, null);
			}
			return result;
		}
	}
}
